﻿using NewAI.Game;
using NewAI.Tools;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static NewAI.FSM.TankFSM.RoundAnalyzer;

namespace NewAI.FSM.TankFSM
{
    public class TankAI : IBaseEntity
    {
        public State<TankAI> CurrentState;

        public FSMMessage ActionObjToJsonAnalyzer = new FSMMessage();

        public TankInfo MyTankInfo { set; get; }                     //当前坦克相关信息
        public TankInfo TargetTankInfo { set; get; }                 //目标敌人(最近的敌人)相关信息
        public CoinInfo TargetCoinInfo { set; get; }                 //目标金矿(最近的金矿)相关信息
        public TankInfo NearliestTankInfo { set; get; }              //目标盟军（最近的友军）相关信息
        public byte[,] Map { set; get; }                             //障碍物+子弹地图
        public Goods[,] ElementMap { set; get; }                      //元素地图
        public bool IfHasAssistanceMission { set; get; } = false;    //是否已经接收了援助任务
        public BulletInfo DangerousBulletInfo { set; get; }          //最近的子弹
        public int TeamID { set; get; }                              //团队ID
        public bool IsSurvival { set; get; } = true;
        public FSMMessage FinishTankActionMessage = new FSMMessage();
        public float ThreatDegree { set; get; } = 1;
        public float ProfitDegree { set; get; } = 1;
        public Point Position { set; get; }
        public string FightMethod { set; get; }

        public DefaultFireAndMoveDirection DefaultFightDirection { set; get; }
        public DefaultFireAndMoveDirection DefaultGetCoinDirection { set; get; }
        public DefaultFireAndMoveDirection DefaultWithdrawDirection { set; get; }
        public DefaultFireAndMoveDirection DefaultAskForAssistanceDirection { set; get; }

        //TODO:本代码仅供调试使用
        public double CalculateTime { set; get; }

        #region 固定值

        //最大敌人距离
        public static int MaxEnemyDistance { set; get; } = 30;

        //最大预测敌人子弹移动回合数
        public static int MaxForecastBulletsMoveRound { set; get; } = 4;

        //最大预测敌人距离（A*距离，超出这个距离就不认为该坦克在当前坦克的附近）
        public static int MaxAroundEnemyTankDistance = 30;

        //最大预测友军距离
        public static int MaxAroundOurTankDistance = 30;

        //最大金矿距离
        public static int MaxAroundCoinDistance = 30;

        #endregion

        #region 风险度权值
        //敌人坦克距离权值
        public static float EnemyTanksDistanceThreatDegreeWeight = 10;

        //子弹威胁度权值
        public static float BulletDistanceThreatDegreeWeight = 10;

        //一定范围内敌方坦克数量权值
        public static float EnemyTanksCountThreatDegreeWeight = 10;

        //一定范围内的友军数量权值
        public static float OurTanksCountThreatDegreeWeight = 10;

        //一定范围内友军的平均距离权值
        public static float OurTanksDistanceThreatDegreeWeight = 10;

        //剩余复活次数权值
        public static float RemainLifeThreatDegreeWeight = 10;









        #endregion

        #region 收益度权值
        //附近金币量个数收益度权值
        public static float AroundCoinsProfitDegreeWeight = 10;

        //附近金币价值收益度权值
        public static float AroundCoinsValueProfitDegreeWeight = 10;

        //能否一回合干掉坦克收益度权值
        public static float KillTanksProfitDegreeWeight = 10;
        #endregion

        public void Update()
        {
            CurrentState.Execute(this);
        }

        public int TankID { get; private set; }
        public int RoundID { get; set; }

        public TankAI(int tankID)
        {
            TankID = tankID;
            PubliceMessage.CloseAllMessage.OnEvent += OnCloseAll;
        }

        public void ChangeState(State<TankAI> state)
        {
            if (CurrentState != null)
                CurrentState.Exit(this);
            CurrentState = state;
            CurrentState.Enter(this);
        }

        public void OnReceiveLegStartMessage(object sender, FSMEventEventArg args)
        {
            ChangeState(new ResetPublicVariableState(args.Obj as NewAI.Game.LegStartData));
        }

        public void OnReceiveRoundMessage(object sender, FSMEventEventArg args)
        {
            ChangeState(new AILogicState(args.Obj as NewAI.Game.RoundData));
        }

        public void OnReceiveLegEndMessage(object sender, FSMEventEventArg args)
        {

        }

        public void OnCloseAll(object sender, FSMEventEventArg args)
        {
            if (CurrentState != null)
            {
                CurrentState.Exit(this);
                CurrentState = null;
            }
        }

        /// <summary>
        /// 预测后提示坦克撤离
        /// </summary>
        public void NoticeTankWithdraw()
        {
            if (IfHasAssistanceMission == true)
                return;
            ChangeState(new TankWithdrawState());
        }

        /// <summary>
        /// 预测后提示坦克采矿
        /// </summary>
        public void NoticeTankGetCoin()
        {
            if (IfHasAssistanceMission == true)
                return;
            ChangeState(new TankGetCoinsState());
        }

        /// <summary>
        /// 预测后提示坦克战斗
        /// </summary>
        public void NoticeTankTOFight()
        {
            if (IfHasAssistanceMission == true)
                return;
            ChangeState(new TankFightState());
        }

        /// <summary>
        /// 预测后提示坦克发出援助请求
        /// </summary>
        public void NoticeTankAskForAssistance()
        {
            if (IfHasAssistanceMission == true)
                return;
            else
            {
                FightMethod = "求援";
                ChangeState(new TankRequireAssistanceState());
            }
        }



        /// <summary>
        /// 导航到指定坐标点，获取移动提示
        /// </summary>
        /// <param name="endPoint"></param>
        /// <returns>行动方向</returns>
        public Direction? UseAstarGetCloseToAPoint(Point endPoint)
        {
            Direction? movDir;
            List<Point> path;
            try
            {
                AStarPro.Astar(Map, MyTankInfo.Pos, endPoint, out path);
                if (path.Count <= 1)
                {
                    movDir = null;
                    return movDir;
                }
                else
                {
                    if (path[1].X - path[0].X > 0)
                    {
                        movDir = Direction.Right;
                    }
                    else if (path[1].X - path[0].X < 0)
                        movDir = Direction.Left;
                    else if (path[1].Y - path[0].Y > 0)
                        movDir = Direction.Down;
                    else if (path[1].Y - path[0].Y < 0)
                        movDir = Direction.Up;
                    else
                    {
                        movDir = null;
                        PubliceMessage.DebugMessage.Call(null, new FSMEventEventArg("错误！导航目标点设置错误\r\n"));
                    }

                    return movDir;
                }

            }
            catch (Exception)
            {
                movDir = null;
                return movDir;
            }
        }

        /// <summary>
        /// 构建及发送当前坦克的Action指令
        /// </summary>
        /// <param name="fireDirection"></param>
        /// <param name="movDirection"></param> 
        public void SendActionObj(Direction? fireDirection, Direction? movDirection, BulletType bulletType)
        {
            ActionObj obj = new ActionObj(GV.OurTeam.TeamID, MyTankInfo.TankID, movDirection, fireDirection, bulletType);
            ActionObjToJsonAnalyzer.Call(null, new FSMEventEventArg(obj));
        }


        //#region 无指令开火决策
        ///// <summary>
        ///// 在没有明确的开火命令下，开火决策
        ///// </summary>
        ///// <param name="movDir"></param>
        ///// <returns></returns>
        //public Direction? FireDecisionWithoutSureOrder(Direction? movDir, out BulletType bulletType)
        //{
        //    Direction? firDir;
        //    if (movDir != null)
        //    {
        //        if (IsBrickWallOnMyWay(movDir))
        //        {
        //            firDir = movDir;
        //            bulletType = BulletType.Normal;
        //            return firDir;
        //        }
        //        else if (IsIronWallOnMyWay(movDir))
        //        {
        //            if (MyTankInfo.HasSuperBullet)
        //            {
        //                firDir = movDir;
        //                bulletType = BulletType.Super;
        //                return firDir;
        //            }
        //        }
        //    }

        //    if (IfDangerBulletInLineWithMyTank())
        //    {
        //        //危险子弹在同一条直线上
        //        if (DangerousBulletInfo.pos.X == MyTankInfo.Pos.X)
        //        {
        //            if (DangerousBulletInfo.pos.Y - MyTankInfo.Pos.Y < 0)
        //                firDir = Direction.Up;
        //            else if (DangerousBulletInfo.pos.Y - MyTankInfo.Pos.Y > 0)
        //                firDir = Direction.Down;
        //            else
        //            {
        //                firDir = null;
        //            }
        //        }
        //        else if (DangerousBulletInfo.pos.Y == MyTankInfo.Pos.Y)
        //        {
        //            if (DangerousBulletInfo.pos.X - MyTankInfo.Pos.X < 0)
        //            {
        //                firDir = Direction.Left;
        //            }
        //            else if (DangerousBulletInfo.pos.X - MyTankInfo.Pos.X > 0)
        //            {
        //                firDir = Direction.Right;
        //            }
        //            else
        //            {
        //                firDir = null;
        //                PubliceMessage.DebugMessage.Call(null, new FSMEventEventArg("错误！危险子弹坐标出错\r\n"));
        //            }
        //        }
        //        else
        //            firDir = null;
        //        bulletType = BulletType.Normal;
        //        return firDir;
        //    }
        //    else
        //    {
        //        firDir = null;
        //        bulletType = BulletType.Normal;
        //        return firDir;
        //    }
        //}

        ///// <summary>
        ///// AStar导出的下一步的格子是否是砖墙
        ///// </summary>
        ///// <param name="movDir"></param>
        ///// <returns></returns>
        //private bool IsBrickWallOnMyWay(Direction? movDir)
        //{
        //    Point point;
        //    switch (movDir)
        //    {
        //        case Direction.Up:
        //            point = new Point(MyTankInfo.Pos.X, MyTankInfo.Pos.Y - 1);
        //            if (IsBrickWall(point))
        //                return true;
        //            else
        //                return false;
        //        case Direction.Down:
        //            point = new Point(MyTankInfo.Pos.X, MyTankInfo.Pos.Y + 1);
        //            if (IsBrickWall(point))
        //                return true;
        //            else
        //                return false;
        //        case Direction.Left:
        //            point = new Point(MyTankInfo.Pos.X - 1, MyTankInfo.Pos.Y);
        //            if (IsBrickWall(point))
        //                return true;
        //            else
        //                return false;
        //        case Direction.Right:
        //            point = new Point(MyTankInfo.Pos.X + 1, MyTankInfo.Pos.Y);
        //            if (IsBrickWall(point))
        //                return true;
        //            else
        //                return false;
        //        default:
        //            return false;
        //    }
        //}

        ///// <summary>
        ///// AStar导出的下一步的格子是否是铁墙
        ///// </summary>
        ///// <param name="movDir"></param>
        ///// <returns></returns>
        //private bool IsIronWallOnMyWay(Direction? movDir)
        //{
        //    Point point;
        //    switch (movDir)
        //    {
        //        case Direction.Up:
        //            point = new Point(MyTankInfo.Pos.X, MyTankInfo.Pos.Y - 1);
        //            if (IsIronWall(point))
        //                return true;
        //            else
        //                return false;
        //        case Direction.Down:
        //            point = new Point(MyTankInfo.Pos.X, MyTankInfo.Pos.Y + 1);
        //            if (IsIronWall(point))
        //                return true;
        //            else
        //                return false;
        //        case Direction.Left:
        //            point = new Point(MyTankInfo.Pos.X - 1, MyTankInfo.Pos.Y);
        //            if (IsIronWall(point))
        //                return true;
        //            else
        //                return false;
        //        case Direction.Right:
        //            point = new Point(MyTankInfo.Pos.X + 1, MyTankInfo.Pos.Y);
        //            if (IsIronWall(point))
        //                return true;
        //            else
        //                return false;
        //        default:
        //            return false;
        //    }
        //}

        ///// <summary>
        ///// 判断指定点是否是砖墙
        ///// </summary>
        ///// <param name="point"></param>
        ///// <returns></returns>
        //private bool IsBrickWall(Point point)
        //{
        //    if (point.X < 0 || point.X > GV.MapWidth - 1 || point.Y < 0 || point.Y > GV.MapHeight - 1)
        //    {
        //        return false;
        //    }

        //    if (ElementMap[point.X, point.Y] != null && ElementMap[point.X, point.Y].ElementType == ElementType.BrickWall)
        //        return true;
        //    else
        //        return false;
        //}

        ///// <summary>
        ///// 判断指定点是否是铁墙
        ///// </summary>
        ///// <param name="point"></param>
        ///// <returns></returns>
        //private bool IsIronWall(Point point)
        //{
        //    if (ElementMap[point.X, point.Y] != null && ElementMap[point.X, point.Y].ElementType == ElementType.IronWall)
        //        return true;
        //    else
        //        return false;
        //}

        ///// <summary>
        ///// 判断最近的一颗子弹是否与本坦克在同一直线上
        ///// </summary>
        ///// <returns></returns>
        //private bool IfDangerBulletInLineWithMyTank()
        //{
        //    if (DangerousBulletInfo.pos.X == -1 || DangerousBulletInfo.pos.Y == -1)
        //    {
        //        return false;
        //    }
        //    if (DangerousBulletInfo.pos.X == MyTankInfo.Pos.X || DangerousBulletInfo.pos.Y == MyTankInfo.Pos.Y)
        //        return true;
        //    else
        //        return false;
        //}
        //#endregion


        #region 接收友军援助请求

        /// <summary>
        /// 接收援助请求，回复请求结果，如果决定援助，则向友军移动并进行无指令开火
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnReceiveAssistanceMessage(object sender, FSMEventEventArg args)
        {
            bool ifHelp = DecideWhetherToAssist(sender);
            if (ifHelp)
            {
                IfHasAssistanceMission = true;
                PubliceMessage.DebugMessage.Call(null, new FSMEventEventArg($"正常！{MyTankInfo.TankID}号tank尝试援助{((TankAI)sender).TankID}号坦克\r\n"));
                List<Point> path;
                Direction? movDir;
                BulletType bulletType;
                if (DefaultAskForAssistanceDirection.UseSuperBullet)
                    bulletType = BulletType.Super;
                else
                    bulletType = BulletType.Normal;
                try
                {
                    AStarPro.Astar(Map, MyTankInfo.Pos, ((TankAI)sender).MyTankInfo.Pos, out path);
                    if (path.Count <= 1)
                    {
                        movDir = null;
                    }
                    else
                    {
                        if (path[1].X - path[0].X > 0)
                        {
                            movDir = Direction.Right;
                        }
                        else if (path[1].X - path[0].X < 0)
                            movDir = Direction.Left;
                        else if (path[1].Y - path[0].Y > 0)
                            movDir = Direction.Down;
                        else if (path[1].Y - path[0].Y < 0)
                            movDir = Direction.Up;
                        else
                            movDir = null;
                    }

                }
                catch (Exception)
                {
                    movDir = null;
                }

                if (movDir == null)
                    movDir = DefaultAskForAssistanceDirection.Move;

                ActionObj obj = new ActionObj(GV.OurTeam.TeamID, MyTankInfo.TankID, movDir, DefaultAskForAssistanceDirection.Fire, bulletType);
                ActionObjToJsonAnalyzer.Call(null, new FSMEventEventArg(obj));
            }
        }

        /// <summary>
        /// 判断是否要援助
        /// </summary>
        /// <param name="sender"></param>
        /// <returns></returns>
        private bool DecideWhetherToAssist(object sender)
        {
            TankAI friend = (TankAI)sender;
            if (friend.RoundID == RoundID)
            {
                float myBenefits = ThreatDegree / ProfitDegree;
                float friendBenefits = friend.ThreatDegree / friend.ProfitDegree;
                List<Point> path;
                AStarPro.Astar(Map, MyTankInfo.Pos, friend.MyTankInfo.Pos, out path);
                int instance = path.Count;
                if (instance <= 1)
                {
                    return false;
                }
                else
                {
                    if (friendBenefits > myBenefits && instance <= 15)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }

            }
            else
            {
                PubliceMessage.DebugMessage.Call(null, new FSMEventEventArg($"正常！{friend.TankID}号tank向{TankID}号tank请求的援助不及时,错过Round\r\n"));
                return false;
            }
        }


        #endregion


        //#region 查看友军答复

        //public void AnswerAssistanceToOtherTanks_OnEvent(object sender, FSMEventEventArg e)
        //{
        //    if (e.Msg == "行")
        //    {
        //        ReceiveHelpCount++;

        //        //当第一个同意援助信息传到时，切换到守矿状态，之后再有同意援助信息传到时，不重复进入守矿状态
        //        if (ReceiveHelpCount == 1)
        //            ChangeState(new TankGuardCoinState());
        //    }
        //    else if (e.Msg == "拒绝")
        //    {
        //        ReceiveRefuseHelpCount++;

        //        //如果所有接收到援助信息的友方tank都拒绝援助，向最近友方坦克移动并进行无指令开火
        //        if (ReceiveRefuseHelpCount == CouldHelpTankCount)
        //        {
        //            Direction? movDir;
        //            Direction? firDir;
        //            BulletType bulletType;
        //            movDir = UseAstarGetCloseToAPoint(NearliestTankInfo.Pos);
        //            firDir = FireDecisionWithoutSureOrder(null, out bulletType);
        //            SendActionObj(firDir, movDir, bulletType);
        //        }
        //    }
        //}

        //#endregion
    }
}